/*
 * Copyright (C) 2021 The Chinese Software International Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tonyodev.fetch2.provider;

import com.tonyodev.fetch2.FetchGroup;
import com.tonyodev.fetch2.database.DownloadInfo;
import com.tonyodev.fetch2.model.FetchGroupInfo;
import com.tonyodev.fetch2core.Reason;

import org.jetbrains.annotations.NotNull;

import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * description GroupInfoProvider
 *
 * @author liuluming
 * @since 2021-05-24
 */
public final class GroupInfoProvider {
    private Object lock = new Object();
    private String namespace;
    private DownloadProvider downloadProvider;
    private LinkedHashMap<Integer, WeakReference<FetchGroupInfo>> groupInfoMap = new LinkedHashMap<>();

    /**
     * getGroupInfo
     *
     * @param id 1
     * @param reason reason
     * @return true
     */
    public FetchGroupInfo getGroupInfo(int id, @NotNull Reason reason) {
        synchronized (lock) {
            WeakReference<FetchGroupInfo> weakReference = groupInfoMap.get(id);
            if (weakReference != null) {
                FetchGroupInfo info = weakReference.get();
                if (info == null) {
                    FetchGroupInfo groupInfo = new FetchGroupInfo(id, namespace);
                    groupInfo.update(downloadProvider.getByGroup(id), null, reason);
                    WeakReference<FetchGroupInfo> weakReference1 = new WeakReference<>(groupInfo);
                    groupInfoMap.put(id, weakReference1);
                    return groupInfo;
                } else {
                    return info;
                }
            }else{
                return null;
            }
        }
    }

    public GroupInfoProvider(Object lock, String namespace, DownloadProvider downloadProvider, LinkedHashMap<Integer, WeakReference<FetchGroupInfo>> groupInfoMap) {
        this.lock = lock;
        this.namespace = namespace;
        this.downloadProvider = downloadProvider;
        this.groupInfoMap = groupInfoMap;
    }

    public GroupInfoProvider(String namespace, DownloadProvider downloadProvider) {
        this.namespace = namespace;
        this.downloadProvider = downloadProvider;
    }

    /**
     * getGroupReplace
     *
     * @param id 1
     * @param download download
     * @param reason reason
     * @return true
     */
    public FetchGroup getGroupReplace(int id, @NotNull DownloadInfo download, @NotNull Reason reason) {
        synchronized (lock) {
            FetchGroupInfo groupInfo = getGroupInfo(id, reason);
            groupInfo.update(downloadProvider.getByGroupReplace(id, download), download, reason);
            return groupInfo;
        }

    }

    public GroupInfoProvider(Object lock, LinkedHashMap<Integer, WeakReference<FetchGroupInfo>> groupInfoMap, String namespace, DownloadProvider downloadProvider) {
        this.lock = lock;
        this.groupInfoMap = groupInfoMap;
        this.namespace = namespace;
        this.downloadProvider = downloadProvider;
    }

    /**
     * postGroupReplace
     *
     * @param id 1
     * @param download download
     * @param reason reason
     */
    public void postGroupReplace(int id, @NotNull DownloadInfo download, @NotNull Reason reason) {
        synchronized (lock) {
            WeakReference weakReference = (WeakReference) this.groupInfoMap.get(id);
            FetchGroupInfo groupInfo = weakReference != null ? (FetchGroupInfo) weakReference.get() : null;
            if (groupInfo != null) {
                groupInfo.update(this.downloadProvider.getByGroupReplace(id, download), download, reason);
            }
        }
    }

    public final void clean() {
        synchronized (lock) {
            LinkedHashMap<Integer, WeakReference<FetchGroupInfo>> map = this.groupInfoMap;
            Iterator<Map.Entry<Integer, WeakReference<FetchGroupInfo>>> iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<Integer, WeakReference<FetchGroupInfo>> next = iterator.next();
                if (next.getValue().get() == null) {
                    iterator.remove();
                }
            }
        }
    }

    public void clear() {
        synchronized (lock) {
            this.groupInfoMap.clear();
        }
    }
}

